package com.lianqi.emcpframework.ddd.gencode.controller.writer;

import static com.lianqi.emcpframework.ddd.gencode.controller.writer.PathUtils.getPathFromMethod;
import static com.lianqi.emcpframework.ddd.gencode.utils.MethodUtils.createParamListStr;

import java.math.BigInteger;
import java.util.List;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import com.lianqi.emcpframework.ddd.gencode.Description;
import com.lianqi.emcpframework.ddd.gencode.controller.GenControllerAnnotationParser;
import com.lianqi.emcpframework.ddd.gencode.controller.GenControllerMethodMeta;
import com.lianqi.emcpframework.ddd.gencode.controller.request.RequestBodyInfo;
import com.lianqi.emcpframework.ddd.gencode.controller.request.UpdateMethodRequestBodyParser;
import com.lianqi.emcpframework.ddd.gencode.define.JavaSource;
import com.lianqi.emcpframework.ddd.gencode.define.TypeCollector;
import com.squareup.javapoet.*;

import io.swagger.annotations.ApiOperation;

public final class GenControllerUpdateMethodWriter extends GenControllerMethodWriterSupport {
    public GenControllerUpdateMethodWriter(GenControllerAnnotationParser parser,
        List<GenControllerMethodMeta.MethodMeta> methods, TypeCollector typeCollector) {
        super(parser, methods, typeCollector);
    }

    @Override
    protected void writeMethod(GenControllerMethodMeta.MethodMeta executableElement, JavaSource typeBuilder) {

        String methodName = executableElement.getMethodName();
        Description description = executableElement.getDescription();
        String descriptionStr = description != null ? description.value() : "";
        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(methodName).addModifiers(Modifier.PUBLIC)
            .addAnnotation(ResponseBody.class)
            .addAnnotation(AnnotationSpec.builder(ApiOperation.class).addMember("value", "\"" + descriptionStr + "\"")
                .addMember("nickname", "\"" + methodName + "\"").build())
            .addAnnotation(AnnotationSpec.builder(PostMapping.class)
                .addMember("value", "\"{id}/" + getPathFromMethod(methodName) + "\"").build());
        VariableElement idParam = getIdParam(executableElement.getExecutableElement());
        if (isLong(idParam)) {
            ParameterSpec idParameter = ParameterSpec.builder(TypeName.LONG.box(), "id")
                .addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build();
            methodBuilder.addParameter(idParameter);
        } else if (isBigInter(idParam)) {
            ParameterSpec idParameter = ParameterSpec.builder(ClassName.get(BigInteger.class), "id")
                .addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build();
            methodBuilder.addParameter(idParameter);
        } else {
            ParameterSpec idParameter = ParameterSpec.builder(ClassName.get(String.class), "_id")
                .addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build();
            methodBuilder.addParameter(idParameter);

            methodBuilder.addStatement("$T id = $T.apply(_id)", idParam, idParam);
        }

        RequestBodyInfo requestBodyInfo = new UpdateMethodRequestBodyParser(getPkgName(), getBaseClassName())
            .parseForMethod(executableElement.getExecutableElement());
        if (requestBodyInfo != null) {
            requestBodyInfo.getBodyType().forEach(innerBuilder -> typeBuilder.addType(innerBuilder.build()));
        }
        if (getParser().isWrapper()) {
            if (requestBodyInfo != null) {
                methodBuilder.addParameter(
                    ParameterSpec.builder(requestBodyInfo.getParameterType(), requestBodyInfo.getParameterName())
                        .addAnnotation(RequestBody.class).build());

                methodBuilder.addStatement("this.getApplication().$L($L)", methodName,
                    createParamListStr(requestBodyInfo.getCallParams(), "id"));
            } else {
                methodBuilder.addStatement("this.getApplication().$L($L)", methodName, "id");
            }
            methodBuilder.addStatement("return $T.success(null)", ClassName.bestGuess(getParser().getWrapperCls()));
            methodBuilder.returns(
                ParameterizedTypeName.get(ClassName.bestGuess(getParser().getWrapperCls()), TypeName.VOID.box()));
        } else {
            if (requestBodyInfo != null) {
                methodBuilder.addParameter(
                    ParameterSpec.builder(requestBodyInfo.getParameterType(), requestBodyInfo.getParameterName())
                        .addAnnotation(RequestBody.class).build());

                methodBuilder.addStatement("this.getApplication().$L($L)", methodName,
                    createParamListStr(requestBodyInfo.getCallParams(), "id"));
            } else {
                methodBuilder.addStatement("this.getApplication().$L($L)", methodName, "id");
            }
            methodBuilder.returns(TypeName.VOID);
        }

        typeBuilder.addMethod(methodBuilder.build());
    }

}
